/*
 * Copyright (c) 2011 , Edgar Poce, All rights reserved.
 *
 * Author: Edgar Poce
 *
 * Use, modification and distribution are subject to the "New BSD License"
 * as listed at <url: http://www.opensource.org/licenses/bsd-license.php >.
 */
package com.newen.mojo.protobuf4as3;

/*
 * Copyright 2001-2005 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.PrintWriter;

import org.apache.commons.io.FileUtils;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;

/**
 * Goal which touches a timestamp file.
 * 
 * @goal generate
 */
public class AsCodeGeneratorMojo extends AbstractMojo {

	private static final FilenameFilter PROTO_FILTER = new FilenameFilter() {
		public boolean accept(File dir, String name) {
			return name.toLowerCase().endsWith(".proto");
		}
	};

	private static final FilenameFilter DIRECTORY_FILTER = new FilenameFilter() {
		public boolean accept(File dir, String name) {
			return new File(dir, name).isDirectory();
		}
	};

	/**
	 * Location of the file.
	 * 
	 * @parameter expression="${project.build.directory}/protosources"
	 * @required
	 */
	private String outputDirectory;

	/**
	 * Location of .proto file.
	 * 
	 * @parameter expression="${project.basedir}/src/main/proto"
	 * @required
	 */
	private String protoDirectories;

	/**
	 * Keep temp files
	 * 
	 * @parameter expression="false"
	 * @required
	 */
	private boolean keepTempFiles;

	private final File tempDir = new File(System.getProperty("java.io.tmpdir"));

	/** @parameter default-value="${plugin.artifacts}" */
	private java.util.List<Artifact> pluginArtifacts;

	public void execute() throws MojoExecutionException {
		getLog().info("executing proto as code generator");
		getLog().info("As generator. Sources:  " + protoDirectories);
		getLog().info("As generator. Target:  " + outputDirectory);
		
		String[] fileNames = this.protoDirectories.split(",");
		for (String fileName : fileNames) {
			this.processProtoDirectory(new File(fileName.trim()));	
		}
		
	}
	
	private void processProtoDirectory(File protoDirectory) throws MojoExecutionException {
		File outputDirectory = new File(this.outputDirectory);
		
		// create temporary folder
		outputDirectory.mkdirs();

		// dependencies needed to run the compiler
		Artifact as3compiler = this
				.getAs3CompilerArtifact("protoc-gen-as3-compiler");
		Artifact protobuf = this.getAs3CompilerArtifact("protobuf-java");

		// run generator
		AsCodeGenerator generator = new AsCodeGenerator(this.tempDir,
				as3compiler, protobuf, getLog());
		try {
			generator.init();
			getLog().info("as code generator initialized");
			this.searchAndCompileProto(generator, outputDirectory, protoDirectory);
		} catch (Exception e) {
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			PrintWriter writer = new PrintWriter(baos);
			e.printStackTrace(writer);
			writer.flush();
			writer.close();
			throw new MojoExecutionException("unable to run protoc. "
					+ e.getClass().getName() + " " + e.getMessage() + "\n"
					+ new String(baos.toByteArray()), e);
		} finally {
			if (!this.keepTempFiles) {
				generator.clean();	
			}
		}
		
	}

	private Artifact getAs3CompilerArtifact(String name)
			throws MojoExecutionException {
		for (Artifact artifact : pluginArtifacts) {
			if (artifact.getArtifactId().equals(name)
					&& artifact.getFile().exists()) {
				return artifact;
			}
		}
		throw new MojoExecutionException(name + " artifact not found");
	}

	/**
	 * Searches recursively proto files
	 */
	private void searchAndCompileProto(AsCodeGenerator generator, File outputDirectory, File directory)
			throws Exception {
		// Process proto files
		for (File proto : directory.listFiles(PROTO_FILTER)) {
			getLog().info("running generator for: " + proto.getName());
			generator.compileProto(outputDirectory, proto);
		}
		// Search in child directories
		for (File childDirectory : directory.listFiles(DIRECTORY_FILTER)) {
			getLog().info(
					"searching in child directory: " + childDirectory.getName());
			this.searchAndCompileProto(generator, outputDirectory, childDirectory);
		}
	}

}
